home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Xconq 7.1.0 / src / xconq-7.1.0 / curses / cconq.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  28.1 KB  |  1,452 lines  |  [TEXT/R*ch]

  1. /* The main program of the curses interface to Xconq.
  2.    Copyright (C) 1986, 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996
  3.    Stanley T. Shebs.
  4.  
  5. Xconq is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.  See the file COPYING.  */
  9.  
  10. #include "conq.h"
  11. extern void low_send PARAMS ((int id, char *buf));
  12. extern int low_receive PARAMS ((int *id, char *buf, int maxchars,
  13.                 int timeout));
  14. extern void update_debugging PARAMS ((void));
  15. extern void toggle_debugging PARAMS ((int *flagp));
  16. extern char *get_scores PARAMS ((Side *side));
  17. #include "cmdline.h"
  18. #include "cconq.h"
  19. extern void make_generic_image_data PARAMS ((ImageFamily *imf));
  20.  
  21. #ifdef THINK_C
  22. /* This is to get the command line reader in Think C on the Mac. */
  23. #include <console.h>
  24. #endif /* THINK_C */
  25.  
  26. #ifdef __MWERKS__
  27. #define MAC
  28. /* This is to get the command line reader in Metrowerks on the Mac. */
  29. #include <console.h>
  30. #include <sioux.h>
  31. #endif /* __MWERKS__ */
  32.  
  33. static void describe_help PARAMS ((int arg, char *key, char *buf));
  34.  
  35. int announced = FALSE;
  36.  
  37. char *announcemsg = NULL;
  38.  
  39. /* The side of the one human player. */
  40.  
  41. Side *dside = NULL;
  42.  
  43. /* move to where a change has occured */
  44.  
  45. int follow_action;
  46.  
  47. /* The location currently being examined. */
  48.  
  49. int curx, cury;
  50.  
  51. int tmpcurx, tmpcury;
  52.  
  53. /* The unit currently being examined, if any. */
  54.  
  55. Unit *curunit;
  56.  
  57. Unit *tmpcurunit;
  58.  
  59. /* The current interaction mode. */
  60.  
  61. enum mode mode;
  62.  
  63. /* The pushed interaction mode. */
  64.  
  65. enum mode prevmode;
  66.  
  67. /* The current input character. */
  68.  
  69. char inpch;
  70.  
  71. /* The command's numeric argument. */
  72.  
  73. int prefixarg;
  74.  
  75. /* These are used when asking for a unit type. */
  76.  
  77. char *ustr;
  78. int *uvec;
  79. int *bvec;
  80.  
  81. /* length and number of notice lines */
  82.  
  83. int nw, nh;
  84.  
  85. /* last current x and y (-1,-1 initially) */
  86.  
  87. int lastx, lasty;
  88.  
  89. /* current prompt on display */
  90.  
  91. char *text1;
  92. char *text2;
  93.  
  94. /* data about string under construction */
  95.  
  96. int reqstrbeg;
  97. int reqstrend;
  98.  
  99. /* The help window. */
  100.  
  101. struct ccwin *helpwin;
  102.  
  103. /* Cached help info. */
  104.  
  105. HelpNode *cur_help_node;
  106.  
  107. HelpNode *help_help_node;
  108.  
  109. HelpNode *commands_help_node;
  110.  
  111. HelpNode *topics_help_node;
  112.  
  113. struct ccwin *datewin;
  114.  
  115. struct ccwin *sideswin;
  116.  
  117. struct ccwin *toplineswin;
  118.  
  119. struct ccwin *clockwin;
  120.  
  121. /* Display of a piece of the world */
  122.  
  123. struct ccwin *mapwin;
  124.  
  125. /* Unit listing */
  126.  
  127. struct ccwin *listwin;
  128.  
  129. struct ccwin *closeupwin;
  130.  
  131. struct ccwin *sidecloseupwin;
  132.  
  133. /* Map dimensions. */
  134.  
  135. int mw, mh;
  136.  
  137. VP *mvp;
  138.  
  139. /* lower left of viewport in cell coords */
  140.  
  141. int vx, vy;
  142.  
  143. /* Boundaries of viewport in cell coords */
  144.  
  145. int vw, vh;
  146.  
  147. /* 1/2 (rounded down) of above values */
  148.  
  149. int vw2, vh2;
  150.  
  151. int lastvcx, lastvcy;
  152.  
  153. /* Num text lines in unit info window. */
  154.  
  155. int infoh;
  156.  
  157. /* List dimensions. */
  158.  
  159. int lw, lh;
  160.  
  161. /* Side list dimensions. */
  162.  
  163. int sh;
  164.  
  165. /* How to draw the map. */
  166.  
  167. int drawterrain;
  168.  
  169. /* Display units on the map? */
  170.  
  171. int drawunits;
  172.  
  173. /* Display unit names/numbers on the map? */
  174.  
  175. int drawnames;
  176.  
  177. int drawpeople;
  178.  
  179. enum listsides listsides;
  180. int test;
  181. int value;
  182. int sorton;
  183. int sortorder;
  184.  
  185. /* True when the display is up and running. */
  186.  
  187. int active;
  188.  
  189. /* Countdown for when multiple turns autofinishing. */
  190.  
  191. int autofinish_start;
  192.  
  193. int autofinish_count;
  194.  
  195. /* The main program just invokes everything else. */
  196.  
  197. int
  198. main(argc, argv)
  199. int argc;
  200. char *argv[];
  201. {
  202. #ifdef THINK_C
  203.     /* This is how Think C picks up a command line. */
  204.     argc = ccommand(&argv);
  205. #endif
  206. #ifdef __MWERKS__
  207.     /* This is how Metrowerks C picks up a command line. */
  208.     argc = ccommand(&argv);
  209.     /* Configure the SIOUX window. */
  210.     SIOUXSettings.initializeTB = TRUE;
  211.     SIOUXSettings.standalone = FALSE;
  212.     SIOUXSettings.setupmenus = FALSE;
  213.     SIOUXSettings.autocloseonquit = FALSE;
  214.     SIOUXSettings.asktosaveonclose = TRUE;
  215.     SIOUXSettings.showstatusline = TRUE;
  216. #endif
  217. #ifdef MAC
  218.     _maccur_pgm_name = "Cconq";
  219. #endif
  220.     printf("\n              Welcome to Curses Xconq version %s\n\n",
  221.        version_string());
  222.     init_library_path(NULL);
  223.     print_any_news();
  224.     printf("%s", license_string());
  225.     clear_game_modules();
  226.     init_data_structures();
  227.     parse_command_line(argc, argv, general_options);
  228. #ifdef DEBUGGING
  229.     update_debugging();
  230. #endif /* DEBUGGING */
  231.     /* (should volunteer to restore saved game if one found) */
  232.     load_all_modules();
  233.     check_game_validity();
  234.     parse_command_line(argc, argv, variant_options);
  235.     set_variants_from_options();
  236.     parse_command_line(argc, argv, player_options);
  237.     /* Go through once more and complain about anything not used. */
  238.     parse_command_line(argc, argv, leftover_options);
  239.     set_players_from_options();
  240.     make_trial_assignments();
  241.     calculate_globals();
  242.     run_synth_methods();
  243.     final_init();
  244.     assign_players_to_sides();
  245.     /* Run through game calcs, but don't let anything move yet; this
  246.        gives display code better values to work with. */
  247.     run_game(0);
  248.     init_display();
  249.     init_interaction();
  250.     redraw();
  251.     init_signal_handlers();
  252.     while (TRUE) {
  253. #ifdef HAVE_SELECT
  254. please somebody write this code
  255.     run_game(1);
  256. #else
  257.     set_g_use_side_priority(TRUE);
  258.     /* assumes no real-timeness */
  259.     while (run_game(9) > 0)
  260.       ;
  261.     maybe_handle_input(0);
  262. #endif
  263.     }
  264.     /* Humor the compiler. */
  265.     return 0;
  266. }
  267.  
  268. /* Nonempty display name not actually used, but needed to keep things
  269.    straight. */
  270.  
  271. Player *
  272. add_default_player()
  273. {
  274.     Player *player = add_player();
  275.  
  276.     player->name = getenv("USER");
  277.     player->displayname = "term";
  278.     return player;
  279. }
  280.  
  281. /* Set up the basic user interface for a side. */
  282.  
  283. void
  284. init_ui(side)
  285. Side *side;
  286. {
  287.     if (side_wants_display(side)) {
  288.     if (dside == NULL) {
  289.         side->ui = (struct a_ui *) xmalloc(sizeof(int));
  290.         dside = side;
  291.         active = FALSE;
  292.         follow_action = FALSE;
  293.         cur_help_node = NULL;
  294.         mode = prevmode = SURVEY;
  295.         prefixarg = -1;
  296.     } else {
  297.         fprintf(stderr, "More than one side wanted a display!\n");
  298.         exit(1);
  299.     }
  300.     }
  301. }
  302.  
  303. /* Open display, create all the windows we'll need, do misc setup things,
  304.    and initialize some globals to out-of-range values for recognition later. */
  305.  
  306. void
  307. init_display()
  308. {
  309.     int x, y, i;
  310.  
  311.     if (dside == NULL) {
  312.     fprintf(stderr, "No side wanted a display!\n");
  313.     exit(1);
  314.     }
  315.     Dprintf("Will try to open screen as display...\n");
  316.     /* Go through the standard curses setup sequence. */
  317.     initscr();
  318.     nonl();
  319.     noecho();
  320.     cbreak();
  321.     clear();
  322.     /* Set up random globals. */
  323.     nw = min(BUFSIZE, 60);
  324.     nh = 1;
  325.     text1 = xmalloc (BUFSIZE);
  326.     text2 = xmalloc (BUFSIZE);
  327.     text1[0] = '\0';
  328.     text2[0] = '\0';
  329.     ustr = xmalloc (MAXUTYPES);
  330.     uvec = (int *) xmalloc (MAXUTYPES * sizeof(int));
  331.     bvec = (int *) xmalloc (MAXUTYPES * sizeof(int));
  332.     /* Compute the division of the screen. */
  333.     mw = (2 * COLS) / 3;
  334.     infoh = 4;
  335.     mh = LINES - 2 - infoh - 1;
  336.  
  337.     mvp = new_vp();
  338.     /* Each cell is actually 2 chars or "pixels" wide.  This is the
  339.        difference from the standard power==0 parameters, so we do
  340.        a cheesy thing and tweak the array directly. */
  341.     hws[0] = 2;
  342.     set_view_power(mvp, 0);
  343.     set_view_size(mvp, mw, mh);
  344.  
  345.     lw = COLS - mw - 1;
  346.  
  347.     sh = numsides + 1;
  348.     /* The height of the list window is what's left over after making
  349.        space for the side list and status lines. */
  350.     lh = LINES - sh - 1 - 1;
  351.  
  352.     pick_a_focus(dside, &x, &y);
  353.     set_view_focus(mvp, x, y);
  354.     lastvcx = lastvcy = -1;
  355.     /* Set default values for the display controls. */
  356.     drawterrain = TRUE;
  357.     drawunits = TRUE;
  358.     drawnames = FALSE;  /* they clutter up the screen */
  359.     listsides = allsides;
  360.     curunit = NULL;
  361.     /* Create all the windows. */
  362.     toplineswin = create_window(0, 0, nw, 2);
  363.     datewin = create_window(nw, 0, COLS - nw, 1);
  364.     clockwin = create_window(nw, 1, COLS - nw, 1); 
  365.     closeupwin = create_window(0, 2, mw, infoh);
  366.     mapwin = create_window(0, 2 + infoh, mw, mh + 1);
  367.     sideswin = create_window(mw + 1, 2, lw, sh);
  368.     listwin = create_window(mw + 1, 2 + sh, lw, lh);
  369.     /* Help window covers the screen. */
  370.     helpwin = create_window(0, 0, COLS, LINES);
  371.     /* Set up the initial scroll position of the map. */
  372.     set_scroll();
  373.     /* Make a buffer full of dashes, for use on mode lines. */
  374.     if (dashbuffer == NULL) {
  375.     dashbuffer = xmalloc(COLS + 1);
  376.     for (i = 0; i < COLS; ++i)
  377.       dashbuffer[i] = '-';
  378.     dashbuffer[COLS] = '\0';
  379.     }
  380.     init_ui_chars();
  381.     /* Give the interface's state-saving mechanism a chance to preallocate
  382.        anything it might want to use; allocation is not allowed during saving. */
  383.     ui_save_state(dside);
  384.     active = TRUE;
  385.     Dprintf("Successfully opened display!\n");
  386. }
  387.  
  388. void
  389. init_interaction()
  390. {
  391.     curunit = NULL;
  392.     find_next_and_look();
  393.     if (curunit) {
  394.     mode = MOVE;
  395.     } else {
  396.     mode = SURVEY;
  397.     move_survey(mvp->vcx, mvp->vcy);
  398.     }
  399.     show_cursor();
  400.     /* Set up some cconq-specific help nodes. */
  401.     if (cur_help_node == NULL) {
  402.     help_help_node =
  403.       add_help_node("help", describe_help, 0, first_help_node);
  404.     commands_help_node =
  405.       add_help_node("commands", describe_commands, 0, first_help_node);
  406.     topics_help_node =
  407.       add_help_node("topics", describe_topics, 0, first_help_node);
  408.     cur_help_node = topics_help_node;
  409.     }
  410.     /* By default, require manual `return' to finish each turn. */
  411.     set_autofinish(dside, FALSE);
  412. }
  413.  
  414. /* Windows in curses are just simple bounding boxes. */
  415.  
  416. struct ccwin *
  417. create_window(x, y, w, h)
  418. int x, y, w, h;
  419. {
  420.     struct ccwin *newwin;
  421.  
  422.     if (x + w > COLS)
  423.       w = COLS - x;
  424.     if (y + h > LINES)
  425.       h = LINES - y;
  426.     DGprintf("Creating %dx%d window at %d,%d\n", w, h, x, y);
  427.  
  428.     newwin = (struct ccwin *) xmalloc(sizeof(struct ccwin));
  429.     newwin->x = x;  newwin->y = y;
  430.     newwin->w = w;  newwin->h = h;
  431.     return newwin;
  432. }
  433.  
  434. /* Generic input character acquisition. */
  435.  
  436. /* (should have a global that indicates whether this is in a modal
  437.    place, then run_game not called on timeout, but waits until out
  438.    of modal thing (perhaps aborts modal dialog automatically, then runs?) */
  439.  
  440. int
  441. wait_for_char()
  442. {
  443.     show_cursor();
  444.     /* Only take 7-bit chars. */
  445.     inpch = getch() & 0177;
  446.     return inpch;
  447. }
  448.  
  449. void
  450. maybe_handle_input(tmout)
  451. int tmout;
  452. {
  453.     Unit *unit;
  454.  
  455.     if (active_display(dside)) {
  456.     if (mode == MOVE) {
  457.         if (curunit != NULL
  458.             && in_play(curunit)
  459.         && (curunit->act
  460.         && curunit->act->acp > 0)  /* should be "above min"? */
  461.             && (curunit->plan
  462.             && !curunit->plan->asleep
  463.             && !curunit->plan->reserve
  464.             && !curunit->plan->delayed)
  465.         ) {
  466.         /* should scroll over to unit */
  467.         } else {
  468.         unit = autonext_unit_inbox(dside, curunit, mvp);
  469.         if (unit
  470.             && unit->plan
  471.             && !unit->plan->asleep
  472.             && !unit->plan->reserve
  473.             && !unit->plan->delayed
  474.             && unit->plan->waitingfortasks
  475.             ) {
  476.             make_current(unit);
  477.         } else {
  478.             make_current(autonext_unit(dside, curunit));
  479.         }
  480.         }
  481.     }
  482. #ifdef HAVE_SELECT
  483. please somebody write this code
  484. #else
  485.     wait_for_char();
  486. #endif
  487.     /* Program will not work without following due to compiler bug. (?) */
  488.     Dprintf("key is %c", inpch); 
  489.     /* Interpret the input. */
  490.     interpret_input();
  491.     }
  492. }
  493.  
  494. void
  495. interpret_input()
  496. {
  497.     int dir;
  498.  
  499.     if (inpch == REDRAW) {
  500.     /* Redraw everything but leave the interaction state unchanged. */
  501.     redraw();
  502.     } else if (mode == HELP) {
  503.     interpret_help();
  504.     } else if (isdigit(inpch)) {
  505.     /* Build up a numeric prefix argument. */
  506.     if (prefixarg < 0) {
  507.         prefixarg = 0;
  508.     } else {
  509.         prefixarg *= 10;
  510.     }
  511.     prefixarg += (inpch - '0');
  512.     sprintf(text1, "Arg: %d", prefixarg);
  513.     show_toplines();
  514.     } else {
  515.     clear_toplines();
  516.     if ((dir = iindex(inpch, dirchars)) >= 0) {
  517.         if (prefixarg < 0)
  518.           prefixarg = 1;
  519.         do_dir_2(dir, prefixarg);
  520.     } else if ((dir = iindex(lowercase(inpch), dirchars)) >= 0) {
  521.         if (prefixarg < 0)
  522.           prefixarg = 9999;
  523.         if (mode == SURVEY)
  524.           prefixarg = 10;
  525.         do_dir_2(dir, prefixarg);
  526.     } else {
  527.         execute_command();
  528.     }
  529.     /* Reset the arg so we don't get confused next time around */
  530.     prefixarg = -1;
  531.     }
  532. }
  533.  
  534. /* Interpret a direction character. */
  535.  
  536. void
  537. do_dir_2(dir, n)
  538. int dir, n;
  539. {
  540.     int nx, ny, rslt;
  541.  
  542.     if (mode == SURVEY) {
  543.     if (point_in_dir_n(curx, cury, dir, n, &nx, &ny)) {
  544.         move_survey(nx, ny);
  545.     } else if (n >= 2 && point_in_dir_n(curx, cury, dir, n / 2, &nx, &ny)) {
  546.         move_survey(nx, ny);
  547.     } else {
  548.         xbeep();
  549.     }
  550.     } else if (curunit == NULL) {
  551.     return;  /* no beep? */
  552.     } else if (n > 1) {
  553.     set_move_dir_task(curunit, dir, n);
  554.     } else {
  555.     if (point_in_dir(curx, cury, dir, &nx, &ny)) {
  556.         rslt = advance_into_cell(dside, curunit, nx, ny, unit_at(nx, ny));
  557.         if (!rslt)
  558.           xbeep();
  559.     } else {
  560.         xbeep();
  561.     }
  562.     }
  563. }
  564.  
  565. int
  566. auto_attack_on_move(unit, unit2)
  567. Unit *unit, *unit2;
  568. {
  569.     return TRUE;
  570. }
  571.  
  572. void
  573. move_survey(nx, ny)
  574. int nx, ny;
  575. {
  576.     if (inside_area(nx, ny)) {
  577.     make_current_at(nx, ny);
  578.     } else {
  579.     /* Complain if we're trying to move the cursor offworld. */
  580.     xbeep();
  581.     }
  582. }
  583.  
  584. /* Ensure that given location is visible. */
  585.  
  586. void
  587. put_on_screen(x, y)
  588. int x, y;
  589. {
  590.     if (!in_middle(x, y)) {
  591.     set_view_focus(mvp, x, y);
  592.     center_on_focus(mvp);
  593.     set_map_viewport();
  594.     show_map();
  595.     show_cursor();
  596.     }
  597.     show_closeup();
  598. }
  599.  
  600. /* Prompt for a yes/no answer with a settable default. */
  601.  
  602. int
  603. ask_bool(question, dflt)
  604. char *question;
  605. int dflt;
  606. {
  607.     char ch;
  608.  
  609.     prevmode = mode;
  610.     mode = PROMPT;
  611.     sprintf(text1, "%s [%s]", question, (dflt ? "yn" : "ny"));
  612.     show_toplines();
  613.     ch = wait_for_char();
  614.     if (dflt ? (lowercase(ch) == 'n') : (lowercase(ch) == 'y'))
  615.       dflt = !dflt;
  616.     mode = prevmode;
  617.     clear_toplines();
  618.     return dflt;
  619. }
  620.  
  621. /* Prompt for a type of a unit from player, maybe only allowing some types
  622.    to be accepted.  Also allow specification of no unit type.  We do this
  623.    by scanning the vector, building a string of chars and a vector of
  624.    unit types, so as to be able to map back when done. */
  625.  
  626. int
  627. ask_unit_type(prompt, possibles)
  628. char *prompt;
  629. short *possibles;
  630. {
  631.     char ch;
  632.     int numtypes = 0, u;
  633.  
  634.     for_all_unit_types(u) {
  635.     bvec[u] = 0;
  636.     if (possibles == NULL || possibles[u]) {
  637.         bvec[u] = 1;
  638.         ustr[numtypes] = utype_name_n(u, 1)[0];
  639.         uvec[numtypes] = u;
  640.         numtypes++;
  641.     }
  642.     }
  643.     if (numtypes == 0) {
  644.     return NONUTYPE;
  645.     } else {
  646.     prevmode = mode;
  647.     mode = PROMPT;
  648.     ustr[numtypes] = '\0';
  649.     sprintf(text1, "%s [%s] ", prompt, ustr);
  650.     show_toplines();
  651.     }
  652.     while (1) {
  653.     ch = wait_for_char();
  654.     if (ch == ESCAPE) {
  655.         mode = prevmode;
  656.         clear_toplines();
  657.         return NONUTYPE;
  658.     }
  659.     if (iindex(ch, ustr) >= 0) {
  660.         mode = prevmode;
  661.         clear_toplines();
  662.         return uvec[iindex(ch, ustr)];
  663.     }
  664.     xbeep();
  665.     }
  666. }
  667.  
  668. /* Prompt for a type of a terrain from player, maybe only allowing some types
  669.    to be accepted.  Also allow specification of no terrain type.  We do this
  670.    by scanning the vector, building a string of chars and a vector of
  671.    terrain types, so as to be able to map back when done. */
  672.  
  673. int
  674. ask_terrain_type(prompt, possibles)
  675. char *prompt;
  676. short *possibles;
  677. {
  678.     char ch;
  679.     int numtypes = 0, t, type;
  680.  
  681.     for_all_terrain_types(t) {
  682.     bvec[t] = 0;
  683.     if (possibles == NULL || possibles[t]) {
  684.         bvec[t] = 1;
  685.         ustr[numtypes]
  686.           = (t_char(t) ? t_char(t)[0] : t_type_name(t)[0]);
  687.         uvec[numtypes] = t;
  688.         numtypes++;
  689.     }
  690.     }
  691.     if (numtypes == 0) {
  692.     type = NONTTYPE;
  693.     } else if (numtypes == 1) {
  694.     type = uvec[0];
  695.     bvec[type] = 0;
  696.     } else {
  697.     ustr[numtypes] = '\0';
  698.     sprintf(text1, "%s [%s] ", prompt, ustr);
  699.     show_toplines();
  700.     }
  701.     while (1) {
  702.     ch = wait_for_char();
  703.     if (ch == ESCAPE) {
  704.         clear_toplines();
  705.         return NONTTYPE;
  706.     }
  707.     if (iindex(ch, ustr) >= 0) {
  708.         clear_toplines();
  709.         return uvec[iindex(ch, ustr)];
  710.     }
  711.     xbeep();
  712.     }
  713. }
  714.  
  715. /* Ask for a direction. */
  716.  
  717. int
  718. ask_direction(prompt, dirp)
  719. char *prompt;
  720. int *dirp;
  721. {
  722.     char ch;
  723.  
  724.     prevmode = mode;
  725.     mode = PROMPTXY;
  726.     sprintf(text1, "%s", prompt);
  727.     sprintf(text2, " [direction keys]");
  728.     show_toplines();
  729.     save_cur();
  730.     while (1) {
  731.     ch = wait_for_char();
  732.     if (ch == ESCAPE) {
  733.         restore_cur();
  734.         mode = prevmode;
  735.         clear_toplines();
  736.         show_cursor();
  737.         return FALSE;
  738.     }
  739.     *dirp = iindex(ch, dirchars);
  740.     if (*dirp >= 0) {
  741.         restore_cur();
  742.         mode = prevmode;
  743.         clear_toplines();
  744.         show_cursor();
  745.         return TRUE;
  746.     } else {
  747.         xbeep();
  748.     }
  749.     }
  750. }
  751.  
  752. /* User is asked to pick a position on map.  This will iterate until
  753.    '.' designates the final position. */
  754.  
  755. int
  756. ask_position(prompt, xp, yp)
  757. char *prompt;
  758. int *xp, *yp;
  759. {
  760.     char ch;
  761.     int dir, nx, ny;
  762.  
  763.     prevmode = mode;
  764.     mode = PROMPTXY;
  765.     sprintf(text1, "%s", prompt);
  766.     sprintf(text2, " [direction keys to move, '.' to set]");
  767.     show_toplines();
  768.     save_cur();
  769.     while (1) {
  770.     ch = wait_for_char();
  771.     if (ch == '.') {
  772.         *xp = curx;  *yp = cury;
  773.         restore_cur();
  774.         mode = prevmode;
  775.         clear_toplines();
  776.         show_cursor();
  777.         return TRUE;
  778.     }
  779.     if (ch == ESCAPE) {
  780.         restore_cur();
  781.         mode = prevmode;
  782.         clear_toplines();
  783.         show_cursor();
  784.         return FALSE;
  785.     }
  786.     if ((dir = iindex(ch, dirchars)) >= 0) {
  787.         point_in_dir(curx, cury, dir, &nx, &ny);
  788.         if (inside_area(nx, ny)) {
  789.         curx = nx;  cury = ny;
  790.         put_on_screen(curx, cury);
  791.         show_cursor();
  792.         } else {
  793.         xbeep();
  794.         }
  795.     } else {
  796.         xbeep();
  797.     }
  798.     }
  799. }
  800.  
  801. /* Save away the currently selected position. */
  802.  
  803. void
  804. save_cur()
  805. {
  806.     tmpcurx = curx;  tmpcury = cury;
  807.     tmpcurunit = curunit;
  808. }
  809.  
  810. /* Restore the saved "cur" slots. */
  811.  
  812. void
  813. restore_cur()
  814. {
  815.     curx = tmpcurx;  cury = tmpcury;
  816.     curunit = tmpcurunit;
  817. }
  818.  
  819. /* Read a string from the prompt window.  Deletion is allowed, and a
  820.    cursor is displayed. */
  821.  
  822. int
  823. ask_string(prompt, dflt, strp)
  824. char *prompt, *dflt, **strp;
  825. {
  826.     char ch;
  827.     int done = FALSE, rslt = FALSE;
  828.  
  829.     sprintf(text1, "%s ", prompt);
  830.     reqstrbeg = strlen(text1);
  831.     /* If a default was supplied, add it. */
  832.     if (dflt != NULL)
  833.       strcat(text1, dflt);
  834.     reqstrend = strlen(text1);
  835.     prevmode = mode;
  836.     mode = PROMPT;
  837.     show_toplines();
  838.     while (!done) {
  839.     ch = wait_for_char();
  840.     switch (ch) {
  841.       case '\r':
  842.       case '\n':
  843.         /* Return a copy of the part of the buffer that was typed into. */
  844.         if (strp != NULL)
  845.           *strp = copy_string(text1 + reqstrbeg);
  846.         done = TRUE;
  847.         rslt = TRUE;
  848.         break;
  849.       case ESCAPE:
  850.         xbeep();
  851.         done = TRUE;
  852.         break;
  853.       case BACKSPACE:
  854.       case 0x7f:
  855.         if (reqstrend > reqstrbeg) {
  856.         --reqstrend;
  857.         } else {
  858.         xbeep();
  859.         }
  860.         break;
  861.       default:
  862.         if (reqstrend < BUFSIZE-2) {
  863.         /* Insert the character. */
  864.         (text1)[reqstrend++] = ch;
  865.         } else {
  866.         xbeep();
  867.         }
  868.     }
  869.     /* Make sure we're always properly terminated. */
  870.     (text1)[reqstrend] = '\0';
  871.     show_toplines();
  872.     }
  873.     /* We're done, put everything back the way it was. */
  874.     mode = prevmode;
  875.     clear_toplines();
  876.     show_cursor();
  877.     return rslt;
  878. }
  879.  
  880. /* Ask for a side. */
  881.  
  882. Side *
  883. ask_side(prompt, dflt)
  884. char *prompt;
  885. Side *dflt;
  886. {
  887.     char ch;
  888.     Side *rslt = dflt;
  889.  
  890.     prevmode = mode;
  891.     mode = PROMPT;
  892.     sprintf(text1, "%s ", prompt);
  893.     show_toplines();
  894.     while (1) {
  895.     show_cursor();
  896.     ch = wait_for_char();
  897.     if (ch == ESCAPE) {
  898.         rslt = dflt;
  899.         break;
  900.     }
  901.     if (between('0', ch, '9')) {
  902.         rslt = side_n(ch - '0');
  903.         break;
  904.     }
  905.     if (ch == '\r' || ch == '\n')
  906.       break;
  907.     xbeep();
  908.     }
  909.     mode = prevmode;
  910.     clear_toplines();
  911.     return rslt;
  912. }
  913.  
  914. int
  915. ask_unit(prompt, unitp)
  916. char *prompt;
  917. Unit **unitp;
  918. {
  919.     char ch;
  920.     int ndirs, dir, nx, ny;
  921.     Unit *nextocc;
  922.  
  923.     *unitp = NULL;
  924.     prevmode = mode;
  925.     mode = PROMPTXY;
  926.     sprintf(text1, "%s", prompt);
  927.     sprintf(text2, " [direction keys to move, '.' to set]");
  928.     show_toplines();
  929.     save_cur();
  930.     while (1) {
  931.     ch = wait_for_char();
  932.     if (ch == '.') {
  933.         restore_cur();
  934.         mode = prevmode;
  935.         clear_toplines();
  936.         show_cursor();
  937.         return TRUE;
  938.     }
  939.     if (ch == ESCAPE) {
  940.         restore_cur();
  941.         mode = prevmode;
  942.         clear_toplines();
  943.         show_cursor();
  944.         return FALSE;
  945.     }
  946.     /* Also recognize the "in" ("occupant") command. */
  947.     if (ch == 'i') {
  948.         if (*unitp != NULL)
  949.           *unitp = find_next_occupant(*unitp);
  950.         make_current(*unitp);
  951.         continue;
  952.     }
  953.     ndirs = char_to_dir(ch, &dir, NULL, NULL);
  954.     if (ndirs > 0) {
  955.         point_in_dir(curx, cury, dir, &nx, &ny);
  956.         if (inside_area(nx, ny)) {
  957.         make_current_at(nx, ny);
  958.         if (curunit != NULL)
  959.           *unitp = curunit;
  960.         } else {
  961.         xbeep();
  962.         }
  963.     } else {
  964.         xbeep();
  965.     }
  966.     }
  967.     return FALSE;
  968. }
  969.  
  970. /* Given a unit, make it be the one that we are "looking at". */
  971.  
  972. void
  973. make_current(unit)
  974. Unit *unit;
  975. {
  976.     curunit = unit;
  977.     if (in_play(unit)) {
  978.     curx = unit->x;  cury = unit->y;
  979.     }
  980.     show_closeup();
  981.     show_cursor();
  982. }
  983.  
  984. /* Give a location, make it be current, and pick a unit there
  985.    to be the current unit. */
  986.  
  987. void
  988. make_current_at(x, y)
  989. int x, y;
  990. {
  991.     Unit *unit;
  992.  
  993.     curx = x;  cury = y;
  994.     curunit = NULL;
  995.     /* Look for a top-level unit to become the new current one. */
  996.     for_all_stack(x, y, unit) {
  997.     if (unit->side == dside) {
  998.         make_current(unit);
  999.         break;
  1000.     }
  1001.     }
  1002.     put_on_screen(curx, cury);
  1003. }
  1004.  
  1005. /* Add 'P' for printing/saving to file (which?). */
  1006. /* (Need individual screen scrolling also) */
  1007.  
  1008. void
  1009. interpret_help()
  1010. {
  1011.     HelpNode *prevhelpnode = cur_help_node;
  1012.     extern int first_visible_help_pos, last_visible_help_pos;
  1013.  
  1014.     switch (inpch) {
  1015.       case ' ':
  1016.         first_visible_help_pos = last_visible_help_pos;
  1017.         show_help();
  1018.     break;
  1019.       case 'n':
  1020.     cur_help_node = cur_help_node->next;
  1021.     break;
  1022.       case 'p':
  1023.     cur_help_node = cur_help_node->prev;
  1024.     break;
  1025.       case 'b':
  1026.     xbeep();
  1027.     break;
  1028.       case 't':
  1029.     cur_help_node = topics_help_node;
  1030.     break;
  1031.       case '?':
  1032.     cur_help_node = help_help_node;
  1033.     break;
  1034.       case ESCAPE:
  1035.       case 'q':
  1036.     mode = prevmode;
  1037.     redraw();
  1038.     break;
  1039.       default:
  1040.     xbeep();
  1041.     break;
  1042.     }
  1043.     if (prevhelpnode != cur_help_node) {
  1044.         first_visible_help_pos = last_visible_help_pos = 0;
  1045.     show_help();
  1046.     }
  1047. }
  1048.  
  1049. static void
  1050. describe_help(arg, key, buf)
  1051. int arg;
  1052. char *key, *buf;
  1053. {
  1054.     tprintf(buf, "' ' to page down through a node\n");
  1055.     tprintf(buf, "'n' to go to next help node\n");
  1056.     tprintf(buf, "'p' to go to previous node\n");
  1057.     tprintf(buf, "'b' to go back to last node\n");
  1058.     tprintf(buf, "'t' to go to topics list\n");
  1059.     tprintf(buf, "'?' to go to this help info\n");
  1060.     tprintf(buf, "'q' or ESC to go back to game\n");
  1061. }
  1062.  
  1063. /* Reading is usually pretty fast, so don't do anything here. */
  1064.  
  1065. void
  1066. announce_read_progress()
  1067. {
  1068. }
  1069.  
  1070. /* Announce the start of a time-consuming computation. */
  1071.  
  1072. void
  1073. announce_lengthy_process(msg)
  1074. char *msg;
  1075. {
  1076.     n_seconds_elapsed(0);
  1077.     announcemsg = copy_string(msg);
  1078.     if (announcemsg) {
  1079.     printf("%s;", announcemsg);
  1080.     fflush(stdout);
  1081.     announcemsg = NULL;
  1082.     announced = TRUE;
  1083.     }
  1084. }
  1085.  
  1086. void
  1087. announce_progress(percentdone)
  1088. int percentdone;
  1089. {
  1090.     if (n_seconds_elapsed(2)) {
  1091.     printf(" %d%%,", percentdone);
  1092.     fflush(stdout);
  1093.     announced = TRUE;
  1094.     }
  1095. }
  1096.  
  1097. void
  1098. finish_lengthy_process()
  1099. {
  1100.     if (announced) {
  1101.     printf(" done.\n");
  1102.     announced = FALSE;
  1103.     }
  1104. }
  1105.  
  1106. /* This is the basic routine to get out of the program - we assume any
  1107.    game hacking has been taken care of already. */
  1108.  
  1109. void
  1110. exit_cconq()
  1111. {
  1112.     close_displays();
  1113.     /* Leave any commentary on the console. */
  1114.     printf("\n%s\n", exit_commentary(dside));
  1115.     printf("\n%s\n", get_scores(dside));
  1116.     exit(0);
  1117. }
  1118.  
  1119. void
  1120. flush_display_buffers(side)
  1121. Side *side;
  1122. {
  1123.     if (active_display(side)) {
  1124.     refresh();
  1125.     }
  1126. }
  1127.  
  1128. /* A predicate that tests whether our display can validly be written to. */
  1129.  
  1130. int
  1131. active_display(side)
  1132. Side *side;
  1133. {
  1134.     return (side == dside
  1135.         && dside != NULL
  1136.         && side_has_display(dside)
  1137.         && active);
  1138. }
  1139.  
  1140. /* Draw an individual detailed cell, as a row of one, on all maps. */
  1141.  
  1142. void
  1143. update_cell_display(side, x, y, rightnow)
  1144. Side *side;
  1145. int x, y;
  1146. int rightnow;
  1147. {
  1148.     if (active_display(side)) {
  1149.     draw_row(x, y, 1);
  1150.     if (rightnow)
  1151.       refresh();
  1152.     }
  1153. }
  1154.  
  1155. /* Curses updates efficiently, so don't need special routine. */
  1156.  
  1157. void
  1158. update_side_display(side, side2, rightnow)
  1159. Side *side, *side2;
  1160. int rightnow;
  1161. {
  1162.     if (active_display(side)) {
  1163.     show_side_list();
  1164.     if (rightnow)
  1165.       refresh();
  1166.     }
  1167. }
  1168.  
  1169. /* Just change the part of the unit list relevant to the given unit. */
  1170.  
  1171. void
  1172. update_unit_display(side, unit, rightnow)
  1173. Side *side;
  1174. Unit *unit;
  1175. int rightnow;
  1176. {
  1177.     if (active_display(side) && unit != NULL) {
  1178.     if (curunit == unit) {
  1179.         show_closeup();
  1180.         show_map();
  1181.     }
  1182.     show_side_list();
  1183.     show_list();
  1184.     if (rightnow)
  1185.       refresh();
  1186.     }
  1187. }
  1188.  
  1189. void
  1190. update_unit_acp_display(side, unit, rightnow)
  1191. Side *side;
  1192. Unit *unit;
  1193. int rightnow;
  1194. {
  1195.     if (active_display(side)) {
  1196.     }
  1197. }
  1198.  
  1199. void
  1200. update_turn_display(side, rightnow)
  1201. Side *side;
  1202. int rightnow;
  1203. {
  1204.     if (active_display(side)) {
  1205.     show_game_date();
  1206.     if (rightnow)
  1207.       refresh();
  1208.     if (g_turn() >= autofinish_start + autofinish_count) {
  1209.         set_autofinish(dside, FALSE);
  1210.     }
  1211.     }
  1212. }
  1213.  
  1214. void
  1215. update_action_display(side, rightnow)
  1216. Side *side;
  1217. int rightnow;
  1218. {
  1219.     if (active_display(side)) {
  1220.     show_side_list();
  1221.     if (rightnow)
  1222.       refresh();
  1223.     }
  1224. }
  1225.  
  1226. void
  1227. update_action_result_display(side, unit, rslt, rightnow)
  1228. Side *side;
  1229. Unit *unit;
  1230. int rslt, rightnow;
  1231. {
  1232.     Action *action;
  1233.  
  1234.     if (active_display(side)) {
  1235.         action = (unit->act ? &(unit->act->nextaction) : NULL);
  1236.         if (action == NULL)
  1237.           return;
  1238.         DGprintf("%s %s result is %s\n",
  1239.          unit_desig(unit), action_desig(action), hevtdefns[rslt].name);
  1240.     if (rightnow)
  1241.       refresh();
  1242.     }
  1243. }
  1244.  
  1245. void
  1246. update_event_display(side, hevt, rightnow)
  1247. Side *side;
  1248. HistEvent *hevt;
  1249. int rightnow;
  1250. {
  1251.     /* (should add to some sort of history display) */
  1252. }
  1253.  
  1254. void
  1255. update_fire_at_display(side, unit, unit2, m, rightnow)
  1256. Side *side;
  1257. Unit *unit, *unit2;
  1258. int m, rightnow;
  1259. {
  1260.     /* (should flash at target) */
  1261. }
  1262.  
  1263. /* This is for animation of fire-into actions. */
  1264.  
  1265. void
  1266. update_fire_into_display(side, unit, x, y, z, m, rightnow)
  1267. Side *side;
  1268. Unit *unit;
  1269. int x, y, z, m, rightnow;
  1270. {
  1271.     /* (should flash at target) */
  1272. }
  1273.  
  1274. /* Updates to clock need to be sure that display changes immediately. */
  1275.  
  1276. void
  1277. update_clock_display(side, rightnow)
  1278. Side *side;
  1279. int rightnow;
  1280. {
  1281.     if (active_display(side)) {
  1282.     show_clock();
  1283.     show_cursor();
  1284.     if (rightnow)
  1285.       refresh();
  1286.     }
  1287. }
  1288.  
  1289. void
  1290. update_message_display(side, sender, str, rightnow)
  1291. Side *side, *sender;
  1292. char *str;
  1293. int rightnow;
  1294. {
  1295.     if (active_display(side)) {
  1296.     notify(side, "%s", str);
  1297.     if (rightnow)
  1298.       refresh();
  1299.     }
  1300. }
  1301.  
  1302. void
  1303. update_all_progress_displays(str, s)
  1304. char *str;
  1305. int s;
  1306. {
  1307. }
  1308.  
  1309. void
  1310. update_everything()
  1311. {
  1312.     redraw();
  1313. }
  1314.  
  1315. void
  1316. action_point(side, x, y)
  1317. Side *side;
  1318. int x, y;
  1319. {
  1320.     if (!active_display(dside))
  1321.       return;
  1322.     if (!inside_area(x, y))
  1323.       return;
  1324.     /* (should scroll over to make action point visible, but
  1325.         probably not change current point?) */
  1326. }
  1327.  
  1328. void
  1329. close_displays()
  1330. {
  1331.     if (!active_display(dside))
  1332.       return;
  1333.     clear();
  1334.     refresh();
  1335.     endwin();
  1336.     active = FALSE;
  1337.     DGprintf("Display \"%s\" closed.\n", dside->player->displayname);
  1338. }
  1339.  
  1340. /* An init error needs to have the command re-run. */
  1341.  
  1342. void
  1343. low_init_error(str)
  1344. char *str;
  1345. {
  1346.     fprintf(stderr, "Error: %s.\n", str);
  1347.     fflush(stderr);
  1348. }
  1349.  
  1350. /* A warning just gets displayed, no other action is taken. */
  1351.  
  1352. void
  1353. low_init_warning(str)
  1354. char *str;
  1355. {
  1356.     fprintf(stdout, "Warning: %s.\n", str);
  1357.     fflush(stdout);
  1358. }
  1359.  
  1360. /* A run error is fatal. */
  1361.  
  1362. void
  1363. low_run_error(str)
  1364. char *str;
  1365. {
  1366.     close_displays();
  1367.     fprintf(stderr, "Error: %s.\n", str);
  1368.     fflush(stderr);
  1369.     fprintf(stderr, "Saving the game...");
  1370.     write_entire_game_state(error_save_filename());
  1371.     fprintf(stderr, " done.\n");
  1372.     fflush(stderr);
  1373.     exit(1);
  1374. }
  1375.  
  1376. /* Runtime warnings are for when it's important to bug the players,
  1377.    usually a problem with Xconq or a game design. */
  1378.  
  1379. void
  1380. low_run_warning(str)
  1381. char *str;
  1382. {
  1383.     if (active_display(dside)) {
  1384.     notify(dside, "Warning: %s; continue? ", str);
  1385.     wait_for_char();
  1386.     } else {
  1387.     low_init_warning(str);
  1388.     }
  1389. }
  1390.  
  1391. void
  1392. print_form(form)
  1393. Obj *form;
  1394. {
  1395.     print_form_and_value(stdout, form);
  1396. }
  1397.  
  1398. void
  1399. end_printing_forms()
  1400. {
  1401. }
  1402.  
  1403. /* Even a curses interface can do simple "movies". */
  1404.  
  1405. int
  1406. #ifdef __STDC__
  1407. schedule_movie(Side *side, enum movie_type movie, ...)
  1408. #else
  1409. schedule_movie(side, movie)
  1410. Side *side;
  1411. enum movie_type movie;
  1412. #endif
  1413. {
  1414.     return 0;
  1415. }
  1416.  
  1417. void
  1418. play_movies(sidemask)
  1419. SideMask sidemask;
  1420. {
  1421. }
  1422.  
  1423. void
  1424. ui_save_state(side)
  1425. Side *side;
  1426. {
  1427.   Obj *state = lispnil;
  1428.  
  1429.   side->uidata = replace_at_key(side->uidata, "curses", state);
  1430. }
  1431.  
  1432. void
  1433. low_send(id, buf)
  1434. int id;
  1435. char *buf;
  1436. {
  1437. }
  1438.  
  1439. int
  1440. low_receive(id, buf, maxchars, timeout)
  1441. int *id, maxchars, timeout;
  1442. char *buf;
  1443. {
  1444.   return 0;
  1445. }
  1446.  
  1447. void
  1448. make_generic_image_data(imf)
  1449. ImageFamily *imf;
  1450. {
  1451. }
  1452.